home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swags_z.zip / SOUND.SWG / 0061_Multiple Sound Channels.pas < prev    next >
Pascal/Delphi Source File  |  1995-03-03  |  4KB  |  145 lines

  1. {
  2. > - trying to produce a 400hz sound in one channel and a 404hz sound in
  3. > another... How difficult will that be for me?  Do I even need to invest
  4. > in a book, or might someone have some code floating around ... *GRiN*
  5.  
  6. Well, I can help you for the PC Speaker, I've once picked this source up from a
  7. Dutch pascal echo:------------------------------
  8. }
  9.  
  10. Unit SoundU;
  11. Interface
  12. Uses
  13.  Dos;
  14.  
  15. Procedure DoubleSound(Freq1,Freq2,Duration,SampleFrequency:Real);
  16. {Play two tones simulatisly: Does sort of:
  17.  Sound(Freq1) + Sound(Freq2)
  18.  Delay(Duration/SampeFrequency*1000)
  19.  NoSound;
  20. }
  21.  
  22. Procedure Cli;
  23. { disable interrupt }
  24. Inline($fa);
  25.  
  26. Procedure Sti;
  27. { enable interrupt }
  28. Inline($fb);
  29.  
  30. Implementation
  31.  
  32. Type { general multitype record for typecasting }
  33.  mtype = Record
  34.   Case Byte Of
  35.    2: (o,s: Word);
  36.    4: (l: LongInt);
  37.  End;
  38.  
  39. Const
  40.  Clk8253 = 1193180; { Clock input to 8253A-5 timerchip }
  41.  
  42. Var
  43.  old_vector: Pointer; { pointer to original interrupt interrupt }
  44.  dacptr1,dacptr2: Word;{ pointer to start of buffer }
  45.  step1,step2: mtype; { table step value }
  46.  Frac1,Frac2: Word; { fractional part of pointer }
  47.  OnsShotTable: Array[0..255] Of Byte; { Table of Timer 2 ReLoad Values }
  48.  SineTable: Array[0..255] Of Byte; { Sine Table }
  49.  Timer0Reload: Word;
  50.  CountDown: Word;
  51.  factor: Real;
  52.  
  53. {$S-}
  54. procedure Int8; Assembler;
  55. asm
  56.  push ax
  57.  push bx
  58.  push cx
  59.  push ds
  60.  mov ax,Seg @Data
  61.  mov ds,ax
  62.  cmp CountDown,0  { Timeout ? }
  63.  jz @Exit
  64.  dec CountDown
  65.  mov bx,dacptr1  { Get first sample }
  66.  mov ax,step1.o
  67.  add Frac1,ax
  68.  adc bx,step1.s
  69.  mov dacptr1,bx
  70.  and bx,$ff
  71.  mov al,[bx+offset SineTable]
  72.  cbw
  73.  mov cx,ax
  74.  mov bx,dacptr2  { Get second sample }
  75.  mov ax,step2.o
  76.  add Frac2,ax
  77.  adc bx,step2.s
  78.  mov dacptr2,bx
  79.  and bx,$ff
  80.  mov al,[BX+Offset SineTable]
  81.  cbw
  82.  add ax,cx   { Add samples }
  83.  sar ax,1   { Adjust }
  84.  add al,$80   { Signed to Absolute }
  85.  mov bx,Offset OnsShotTable { Now, lookup Timer 2 Reload value }
  86.  xlat
  87.  out $42,al   { Reload timer channel 2 }
  88. @Exit:
  89.  mov al,$20   { send End_Of_Interrupt }
  90.  out $20,al
  91.  pop ds
  92.  pop cx
  93.  pop bx
  94.  pop ax
  95.  sti    { Position not critical }
  96.  iret
  97. end;
  98. {$S+}
  99.  
  100. Procedure DoubleSound(Freq1,Freq2,Duration,SampleFrequency:Real);
  101. Var
  102.  I:Byte;
  103. Begin
  104.  {INIT}
  105.  Timer0Reload:=Round(Clk8253/SampleFrequency);
  106.  SampleFrequency:=Round(Clk8253/Timer0Reload);
  107.  factor:=Clk8253/(SampleFrequency*(256+5));
  108.  For I:=0 To 255 Do OnsShotTable[I]:=1+Round(I*factor);
  109.  For I:=0 To 255 Do SineTable[I]:=Byte(Round(Sin((2*Pi*I)/256)*127));
  110.  { Calculate first SineTable Stepvalue }
  111.  step1.l:=Round(65536.0*freq1*256.0/SampleFrequency);
  112.  dacptr1:=0;
  113.  Frac1:=0;
  114.  { Calculate second SineTable Stepvalue }
  115.  step2.l:=Round(65536.0*freq2*256.0/SampleFrequency);
  116.  dacptr2:=0;
  117.  Frac2:=0;
  118.  { Calculate Timeout value }
  119.  CountDown:=Round(SampleFrequency*duration);
  120.  { OK, time to enable our int8 procedure }
  121.  GetIntVec(8,old_vector);
  122.  cli;
  123.  SetIntVec(8,@Int8);
  124.  { initialize 8253 timer-chip }
  125.  { 8255 PPI, Enable Speaker, Speaker input Gate = output from 8253 channel 2 }
  126.  port[$61]:=port[$61] Or $03;
  127.  port[$43]:=$90; { Channel 2, Read/Write only LSB, Mode 0=OneShot, Binary }
  128.  { Set Interrupt 8 frequency (samplefrequency) }
  129.  port[$43]:=$36; { Channel 0, Read/Write LSB then MSB, Mode 3=SqrW, Binary }
  130.  port[$40]:=Lo(Timer0Reload); { LSB }
  131.  port[$40]:=Hi(Timer0Reload); { MSB }
  132.  sti; { Start PC Speak'ing }
  133.  Repeat
  134.   { BEEP'ING }
  135.  Until CountDown=0;
  136.  cli;
  137.  SetIntVec(8,old_vector); { restore original int8 vector }
  138.  port[$43]:=$36;
  139.  port[$40]:=$00;
  140.  port[$40]:=$00;
  141.  sti;
  142. end; { output_sound }
  143.  
  144. end.
  145.